package com.xbongbong.paas.business.rule;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.domain.entity.PaasFormEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.ProFormHelp;
import com.xbongbong.paas.log.MongoLogHelp;
import com.xbongbong.paas.log.constant.LogMemoConstant;
import com.xbongbong.paas.pojo.FormTitlePoJo;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.paas.util.ItemUtil;
import com.xbongbong.paas.util.TitleUtil;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.businessrule.enums.BusinessLoggerEnum;
import com.xbongbong.pro.form.pojo.RuleTargetPojo;
import com.xbongbong.pro.log.pojo.DetailLogPojo;
import com.xbongbong.pro.log.pojo.dto.RuleBusinessLogDTO;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.RedundantTemplateTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.service.toolbox.help.LogHelp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author 吴峰
 * @version v1.0
 * @date 2019/11/8 14:25
 * @since v1.0
 */
@Component
public class RuleBusinessLogger {

    private static final Logger LOG = LoggerFactory.getLogger(RuleBusinessLogger.class);

    @Resource
    private ProFormHelp proFormHelp;
    @Resource
    private MongoLogHelp mongoLogHelp;
    @Resource
    private LogHelp logHelp;


    @Async(value = "sysLogThreadPool")
    public void writeLog(RuleBusinessLogDTO ruleBusinessLogDTO, List<UpdateDataEntity> valueList) throws XbbException {
        try {
            RuleTargetPojo ruleTargetPojo =ruleBusinessLogDTO.getTarget();
            Map<String, FieldAttrEntity> targetExplain = ruleBusinessLogDTO.getTargetExplain();
            List<PaasFormDataEntityExt> formDataList = ruleBusinessLogDTO.getFormDataList();
            XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.UNKNOWN;
            Boolean isSaas = Objects.equals(SaasMarkEnum.SAAS.getCode(), ruleTargetPojo.getLinkSaasMark());
            if (isSaas) {
                xbbRefTypeEnum = XbbRefTypeEnum.getByCode(ruleTargetPojo.getLinkBusinessType());
            }
            Map<Long, JSONObject> targetMap = new HashMap<>(valueList.size());
            valueList.forEach(item->{
                JSONObject jsonObject = new JSONObject();
                item.getData().forEach(data->{
                    String key = data.getKey();
                    Object value = data.getValue();
                    jsonObject.put(key, value);
                });
                targetMap.put(item.getId(), jsonObject);
            });

            PaasFormEntity paasFormEntity = proFormHelp.getPaasForm(ruleTargetPojo.getFormId(), ruleTargetPojo.getLinkBusinessType(), ruleBusinessLogDTO.getCorpid());
            JSONArray title = JSON.parseArray(paasFormEntity.getCustomTitle());
            // 解析数据
            List<String> content = new ArrayList<>();
            List<FieldAttrEntity> explainList = new ArrayList<>();
            Iterator<String> explainIterator = targetExplain.keySet().iterator();
            while (explainIterator.hasNext()) {
                String key = explainIterator.next();
                explainList.add(targetExplain.get(key));
            }
            Map<Long, JSONObject> sourceMap = new HashMap<>(valueList.size());
            Map<Long, String> titleMap = new HashMap<>(valueList.size());
            List<String> attrNameList = new ArrayList<>();
            for (PaasFormDataEntityExt item : formDataList) {
                JSONObject data = item.getData();
                String serialNo = item.getSerialNo();
                JSONObject result = getData(data);
                item.setData(result);
                // 对已更改的数据进行解析，将数据归类
                if (targetMap.containsKey(item.getDataId())) {
                    JSONObject target = targetMap.get(item.getDataId());
                    Iterator<String> iterator = target.keySet().iterator();
                    JSONObject jsonObject = new JSONObject();
                    while (iterator.hasNext()) {
                        String sourceKey = iterator.next();
                        String key = sourceKey.replace("$.", "");
                        Object value = result.get(key);
                        jsonObject.put(key, value);
                    }
                    // 获取每行的源数据，为了知道原来的数据是什么样的
                    sourceMap.put(item.getDataId(), jsonObject);
                    // 解析每行的被修改的数据
                    JSONObject targetData = getData(targetMap.get(item.getDataId()));
                    Iterator<String> targetIterator = targetData.keySet().iterator();
                    while (targetIterator.hasNext()) {
                        String sourceKey = targetIterator.next();
                        String key = sourceKey.replace("$.", "");
                        attrNameList.add(targetExplain.get(key).getAttrName());
                        targetData.put(key, targetData.get(sourceKey));
                    }
                    targetMap.put(item.getDataId(), targetData);
                }
                if (isSaas) {
                    // 获取saas的日志标题
                    String  opObjectName = getName(xbbRefTypeEnum, data);
                    StringBuilder sb = new StringBuilder();
                    sb = StringUtil.isEmpty(opObjectName) ? sb.append(serialNo) : sb.append(serialNo);
                    if (StringUtil.isNotEmpty(opObjectName)) {
                        sb.append("（").append(opObjectName).append("）").toString();
                    }
                    // 竞争对手流水号如果为空，则不再展示流水号
                    if (Objects.isNull(serialNo) && Objects.equals(XbbRefTypeEnum.COMPETITOR.getCode(),ruleTargetPojo.getLinkBusinessType())){
                        opObjectName = opObjectName;
                    }else {
                        opObjectName = sb.toString();
                    }
                    content.add(opObjectName);
                    titleMap.put(item.getDataId(), opObjectName);
                } else{
                    List<FormTitlePoJo> formTitleList = ExplainUtil.getFormTitle(title, targetExplain, result, explainList, item);
                    formTitleList.forEach(titlePoJo->{
                       FieldAttrEntity fieldAttrEntity = targetExplain.get(titlePoJo.getAttr());
                       if (Objects.nonNull(fieldAttrEntity) && ExplainUtil.isCombo(fieldAttrEntity.getFieldType())) {
                           JSONObject jsonObject = new JSONObject();
                           jsonObject.put(titlePoJo.getAttr(), titlePoJo.getValue());
                           Object value = ItemUtil.analysisComboReturnStr(jsonObject, fieldAttrEntity);
                           titlePoJo.setValue(Collections.singletonList(value));
                       }
                    });

                    String titleString = TitleUtil.getTitle(formTitleList);
                    // 封装标题
                    titleMap.put(item.getDataId(), titleString);
                    content.add(titleString);
                }
            }
            Iterator<Long> iterator = sourceMap.keySet().iterator();
            String userName = ruleBusinessLogDTO.getLoginUserName();
            String userId = ruleBusinessLogDTO.getUserId();
            String corpid = ruleBusinessLogDTO.getCorpid();
            RedundantTemplateTypeEnum redundantTemplateTypeEnum = RedundantTemplateTypeEnum.PAAS;
            OperateModuleTypeEnum operateModuleTypeEnum = OperateModuleTypeEnum.PAAS_FORM_DATA;
            if (isSaas) {
                redundantTemplateTypeEnum = RedundantTemplateTypeEnum.getByCode(ruleTargetPojo.getLinkBusinessType());
                BusinessLoggerEnum businessLoggerEnum = BusinessLoggerEnum.getByCode(ruleTargetPojo.getLinkBusinessType());
                operateModuleTypeEnum = businessLoggerEnum.getOperateModuleTypeEnum();
            }
            String formName = paasFormEntity.getName();
            while (iterator.hasNext()) {
                Long dataId = iterator.next();
                JSONObject oldObj = sourceMap.get(dataId);
                JSONObject newObj = targetMap.get(dataId);
                JSONObject oldData = new JSONObject();
                oldData.put("data", oldObj);
                JSONObject newData = new JSONObject();
                newData.put("data", newObj);
                String opObjectName = titleMap.get(dataId);
                String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_UPDATE_WORK), userName, formName, opObjectName);
                List<DetailLogPojo> detailArr = logHelp.getDetailArr4Data(corpid, redundantTemplateTypeEnum, targetExplain, oldData, newData);
                mongoLogHelp.buildLog4DetailArr(detailArr, corpid, userId, userName, operateModuleTypeEnum, OperateTypeEnum.RULE_EDIT,
                        dataId.toString(), opObjectName, memo, ruleBusinessLogDTO.getHttpHeader());
            }

        } catch (Exception e) {
            LOG.error("业务规则记录日志报错：", e);
        }
    }

    private JSONObject getData(JSONObject data) {
        JSONObject dataObject = new JSONObject();
        Iterator<String> iterator = data.keySet().iterator();
        while (iterator.hasNext()) {
            String sourceKey = iterator.next();
            String key = sourceKey.replace("$.", "");
            dataObject.put(key, data.get(sourceKey));
        }
        return dataObject;
    }

    public static String getName(XbbRefTypeEnum xbbRefTypeEnum, JSONObject data) throws XbbException{
        return TitleUtil.getName(xbbRefTypeEnum, data);
    }

}
